<!DOCTYPE html>












  


<html class="theme-next pisces use-motion" lang="zh-CN">
<head><meta name="generator" content="Hexo 3.8.0">
  <meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
























<link rel="stylesheet" href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2">

<link rel="stylesheet" href="/css/main.css?v=7.1.0">


  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png?v=7.1.0">


  <link rel="icon" type="image/png" sizes="32x32" href="/images/logo1.jpg?v=7.1.0">


  <link rel="icon" type="image/png" sizes="16x16" href="/images/logo1.jpg?v=7.1.0">


  <link rel="mask-icon" href="/images/logo.svg?v=7.1.0" color="#222">







<script id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Pisces',
    version: '7.1.0',
    sidebar: {"position":"left","display":"post","offset":12,"onmobile":false,"dimmer":false},
    back2top: true,
    back2top_sidebar: false,
    fancybox: false,
    fastclick: false,
    lazyload: false,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>


  




  <meta name="description" content="常量，是一个经常被提出来的问题，但是很多文章在这个上面介绍得并不详细，甚至有很多错误的地方。">
<meta name="keywords" content="C++">
<meta property="og:type" content="article">
<meta property="og:title" content="关于常量的误解">
<meta property="og:url" content="https://luoo.oschina.io/2016/08/06/tech/关于常量的误解/index.html">
<meta property="og:site_name" content="从你的全世界路过">
<meta property="og:description" content="常量，是一个经常被提出来的问题，但是很多文章在这个上面介绍得并不详细，甚至有很多错误的地方。">
<meta property="og:locale" content="zh-CN">
<meta property="og:updated_time" content="2019-04-14T12:28:00.719Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="关于常量的误解">
<meta name="twitter:description" content="常量，是一个经常被提出来的问题，但是很多文章在这个上面介绍得并不详细，甚至有很多错误的地方。">



  <link rel="alternate" href="/atom.xml" title="从你的全世界路过" type="application/atom+xml">



  
  
  <link rel="canonical" href="https://luoo.oschina.io/2016/08/06/tech/关于常量的误解/">



<script id="page.configurations">
  CONFIG.page = {
    sidebar: "",
  };
</script>

  <title>关于常量的误解 | 从你的全世界路过</title>
  












  <noscript>
  <style>
  .use-motion .motion-element,
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-title { opacity: initial; }

  .use-motion .logo,
  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-CN">

  
  
    
  

  <div class="container sidebar-position-left page-post-detail">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta">
    

    <div class="custom-logo-site-title">
      <a href="/" class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">从你的全世界路过</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
    
      
        <p class="site-subtitle">心智渐开，世事渐杂</p>
      
    
    
  </div>

  <div class="site-nav-toggle">
    <button aria-label="切换导航栏">
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>



<nav class="site-nav">
  
    <ul id="menu" class="menu">
      
        
        
        
          
          <li class="menu-item menu-item-home">

    
    
    
      
    

    

    <a href="/" rel="section"><i class="menu-item-icon fa fa-fw fa-home"></i> <br>首页</a>

  </li>
        
        
        
          
          <li class="menu-item menu-item-categories">

    
    
    
      
    

    

    <a href="/categories/" rel="section"><i class="menu-item-icon fa fa-fw fa-th"></i> <br>分类</a>

  </li>
        
        
        
          
          <li class="menu-item menu-item-tags">

    
    
    
      
    

    

    <a href="/tags/" rel="section"><i class="menu-item-icon fa fa-fw fa-tags"></i> <br>标签</a>

  </li>
        
        
        
          
          <li class="menu-item menu-item-archives">

    
    
    
      
    

    

    <a href="/archives/" rel="section"><i class="menu-item-icon fa fa-fw fa-archive"></i> <br>归档</a>

  </li>
        
        
        
          
          <li class="menu-item menu-item-schedule">

    
    
    
      
    

    

    <a href="/schedule/" rel="section"><i class="menu-item-icon fa fa-fw fa-calendar"></i> <br>计划</a>

  </li>
        
        
        
          
          <li class="menu-item menu-item-you">

    
    
    
      
    

    

    <a href="/you/" rel="section"><i class="menu-item-icon fa fa-fw fa-heartbeat"></i> <br>知遇</a>

  </li>
        
        
        
          
          <li class="menu-item menu-item-about">

    
    
    
      
    

    

    <a href="/about/" rel="section"><i class="menu-item-icon fa fa-fw fa-user"></i> <br>关于</a>

  </li>

      
      
    </ul>
  

  

  
</nav>



  



</div>
    </header>

    


    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          
            

          
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="https://luoo.oschina.io/2016/08/06/tech/关于常量的误解/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="方林">
      <meta itemprop="description" content="愿你出走半生，归来仍是少年">
      <meta itemprop="image" content="/images/logo1.jpg">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="从你的全世界路过">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">关于常量的误解

              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">

            
            
            

            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              

              
                
              

              <time title="创建时间：2016-08-06 23:14:25" itemprop="dateCreated datePublished" datetime="2016-08-06T23:14:25+08:00">2016-08-06</time>
            

            
          </span>

          
            <span class="post-category">
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing"><a href="/categories/编程技术/" itemprop="url" rel="index"><span itemprop="name">编程技术</span></a></span>

                
                
              
            </span>
          

          
            
            
              
              <span class="post-comments-count">
                <span class="post-meta-divider">|</span>
                <span class="post-meta-item-icon">
                  <i class="fa fa-comment-o"></i>
                </span>
            
                <span class="post-meta-item-text">评论数：</span>
                <a href="/2016/08/06/tech/关于常量的误解/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count valine-comment-count" data-xid="/2016/08/06/tech/关于常量的误解/" itemprop="commentCount"></span>
                </a>
              </span>
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        <p>常量，是一个经常被提出来的问题，但是很多文章在这个上面介绍得并不详细，甚至有很多错误的地方。</p>
<a id="more"></a>
<h1 id="概述"><a href="#概述" class="headerlink" title="概述"></a><strong>概述</strong></h1><p>为什么要使用const？采用符号常量写出的代码更容易维护；指针常常是边读边移动，而不是边写边移动；<br>许多函数参数是只读不写的。const最常见用途是作为数组的界和switch分情况标号(也可以用枚举符代替)，分类如下：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">常变量：  const 类型说明符 变量名</span><br><span class="line">常引用：  const 类型说明符 &amp;引用名</span><br><span class="line">常对象：  类名 const 对象名</span><br><span class="line">常成员函数：  类名::fun(形参) const</span><br><span class="line">常数组：  类型说明符 const 数组名[大小]</span><br><span class="line">常指针：  const 类型说明符* 指针名 ，类型说明符* const 指针名（分为常量指针和指针常量，怎么区分，后面介绍）</span><br></pre></td></tr></table></figure>
<p><strong>注意</strong>：除了常指针外，const与“类型说明符”或“类名”的位置可以替换。譬如const int a=5;等价于int const a=5;。</p>
<h1 id="常量"><a href="#常量" class="headerlink" title="常量"></a><strong>常量</strong></h1><p>取代了C中的宏定义，声明时必须进行初始化(!c++类中则不然）。const限制了常量的使用方式，并没有描述常量应该如何分配。</p>
<p>如果编译器知道了某const的所有使用，它甚至可以不为该const分配空间。最简单的常见情况就是常量的值在编译时已知，而且不需要分配存储。</p>
<p>用const声明的变量虽然增加了分配空间，但是可以保证类型安全。C标准中，const定义的常量是全局的，C++中视声明位置而定。</p>
<p><strong>优点</strong>：const常量有数据类型，而宏常量没有数据类型。编译器可以对前者进行类型安全检查，而对后者只进行字符替换，没有类型安全检查，并且在字符替换时可能会产生意料不到的错误（边际效应）</p>
<h1 id="指针和常量"><a href="#指针和常量" class="headerlink" title="指针和常量"></a><strong>指针和常量</strong></h1><p>使用指针时涉及到两个对象：该指针本身和被它所指的对象。将一个指针的声明用const“预先固定”将使那个对象而不是使这个指针成为常量。</p>
<p>要将指针本身而不是被指对象声明为常量，必须使用声明运算符<em>const。所以出现在 </em> 之前的const是作为基础类型的一部分：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">char *const cp; //到char的const指针</span><br><span class="line">char const *pc1; //到const char的指针</span><br><span class="line">const char *pc2; //到const char的指针（后两个声明是等同的）</span><br><span class="line">从右向左读的记忆方式：</span><br><span class="line">cp is a const pointer to char. 故pc不能指向别的字符串，但可以修改其指向的字符串的内容</span><br><span class="line">pc2 is a pointer to const char. 故*pc2的内容不可以改变，但pc2可以指向别的字符串</span><br></pre></td></tr></table></figure>
<p><strong>注意</strong>：允许把非 const 对象的地址赋给指向 const 对象的指针,不允许把一个 const 对象的地址赋给一个普通的、非 const 对象的指针。</p>
<p>常量与指针放在一起很容易让人迷糊。对于常量指针和指针常量也不是所有的学习C/C++的人都能说清除。例如：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">const int *m1 = new int(10);</span><br><span class="line">int* const m2 = new int(20);</span><br></pre></td></tr></table></figure>
<p>在上面的两个表达式中，最容易让人迷惑的是const到底是修饰指针还是指针指向的内存区域？其实，只要知道：</p>
<p>const只对它左边的东西起作用，唯一的例外就是const本身就是最左边的修饰符，那么它才会对右边的东西起作用。</p>
<p>根据这个规则来判断，m1应该是常量指针（即，不能通过m1来修改它所指向的内容。）；而m2应该是指针常量（即，不能让m2指向其他的内存模块）。<br>由此可见：</p>
<p>对于常量指针，不能通过该指针来改变所指的内容。即，下面的操作是错误的：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">int i = 10;</span><br><span class="line">const int *pi = &amp;i;</span><br><span class="line">*pi = 100;</span><br><span class="line">因为你在试图通过pi改变它所指向的内容。但是，并不是说该内存块中的内容不能被修改。我们仍然可以通过其他方式去修改其中的值。例如：</span><br><span class="line">// 1: 通过i直接修改。</span><br><span class="line">i = 100;</span><br><span class="line">// 2:　使用另外一个指针来修改。</span><br><span class="line">int *p = (int*)pi;</span><br><span class="line">*p = 100;</span><br></pre></td></tr></table></figure>
<p>实际上，在将程序载入内存的时候，会有专门的一块内存区域来存放常量。但是，上面的i本身不是常量，是存放在栈或者堆中的。我们仍然可以修改它的值。而pi不能修改指向的值应该说是编译器的一个限制。</p>
<p>根据上面const的规则，const int *m1 = new int(10);我们也可写作：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">int const　*m1 = new int(10);</span><br><span class="line">这是，理由就不须作过多说明了。</span><br></pre></td></tr></table></figure>
<p>在函数参数中指针常量时表示不允许将该指针指向其他内容。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">void func_02(int* const p)</span><br><span class="line">&#123;</span><br><span class="line">	int *pi = new int(100);</span><br><span class="line">	//错误！P是指针常量。不能对它赋值。</span><br><span class="line">	p = pi;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main()</span><br><span class="line">&#123;</span><br><span class="line">	int* p = new int(10);</span><br><span class="line">	func_02(p);</span><br><span class="line">	delete p;</span><br><span class="line">	return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>在函数参数中使用常量指针时表示在函数中不能改变指针所指向的内容。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">void func(const int *pi)</span><br><span class="line">&#123;</span><br><span class="line">	//错误！不能通过pi去改变pi所指向的内容！</span><br><span class="line">	*pi = 100;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main()</span><br><span class="line">&#123;</span><br><span class="line">	int* p = new int(10);</span><br><span class="line">	func(p);　</span><br><span class="line">	delete p;</span><br><span class="line">	return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>我们可以使用这样的方法来防止函数调用者改变参数的值。但是，这样的限制是有限的，作为参数调用者，我们也不要试图去改变参数中的值。因此，下面的操作是在语法上是正确的，但是可能破还参数的值：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;iostream&gt;</span><br><span class="line">#include &lt;string&gt;</span><br><span class="line"></span><br><span class="line">void func(const int *pi)</span><br><span class="line">&#123;</span><br><span class="line">	//这里相当于重新构建了一个指针，指向相同的内存区域。当然就可以通过该指针修改内存中的值了。</span><br><span class="line">	int* pp = (int*)pi;</span><br><span class="line">	*pp = 100;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main()</span><br><span class="line">&#123;</span><br><span class="line">	using namespace std;</span><br><span class="line">	int* p = new int(10);</span><br><span class="line">	cout &lt;&lt; &quot;*p = &quot; &lt;&lt; *p &lt;&lt; endl;</span><br><span class="line">	func(p);</span><br><span class="line">	cout &lt;&lt; &quot;*p = &quot; &lt;&lt; *p &lt;&lt; endl;</span><br><span class="line">	delete p;</span><br><span class="line">	return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>const修饰指针的情况，见下式：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">int b = 500;</span><br><span class="line">const int* a = &amp;                  [1]</span><br><span class="line">int const *a = &amp;                  [2]</span><br><span class="line">int* const a = &amp;                  [3]</span><br><span class="line">const int* const a = &amp;            [4]</span><br></pre></td></tr></table></figure>
<p>如果你能区分出上述四种情况，那么，恭喜你，你已经迈出了可喜的一步。不知道，也没关系，我们可以参考《Effectivec++》Item21上的做法，如果const位于星号的左侧，则const就是用来修饰指针所指向的变量，即指针指向为常量；如果const位于星号的右侧，const就是修饰指针本身，即指针本身是常量。因此，[1]和[2]的情况相同，都是指针所指向的内容为常量（const放在变量声明符的位置无关），这种情况下不允许对内容进行更改操作，如不能*a = 3；[3]为指针本身是常量，而指针所指向的内容不是常量，这种情况下不能对指针本身进行更改操作，如a++是错误的；[4]为指针本身和指向的内容均为常量。</p>
<h1 id="常量和引用"><a href="#常量和引用" class="headerlink" title="常量和引用"></a><strong>常量和引用</strong></h1><p>常量与引用的关系稍微简单一点。因为引用就是另一个变量的别名，它本身就是一个常量。也就是说不能再让一个引用成为另外一个变量的别名, 那么他们只剩下代表的内存区域是否可变。即：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">int i = 10;</span><br><span class="line">// 正确：表示不能通过该引用去修改对应的内存的内容。</span><br><span class="line">const int&amp; ri = i;</span><br><span class="line">// 错误！不能这样写。</span><br><span class="line">int&amp; const rci = i;</span><br><span class="line">由此可见，如果我们不希望函数的调用者改变参数的值。最可靠的方法应该是使用引用。下面的操作会存在编译错误：</span><br><span class="line"></span><br><span class="line">void func(const int&amp; i)</span><br><span class="line">&#123;</span><br><span class="line">	// 错误！不能通过i去改变它所代表的内存区域。</span><br><span class="line">	i = 100;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main()</span><br><span class="line">&#123;</span><br><span class="line">	int i = 10;</span><br><span class="line">	func(i);</span><br><span class="line">	return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>这里已经明白了常量与指针以及常量与引用的关系。但是，有必要深入的说明以下。在系统加载程序的时候，系统会将内存分为4个区域：堆区 栈区全局区（静态）和代码区。从这里可以看出，对于常量来说，系统没有划定专门的区域来保护其中的数据不能被更改。也就是说，使用常量的方式对数据进行保护是通过编译器作语法限制来实现的。我们仍然可以绕过编译器的限制去修改被定义为“常量”的内存区域。看下面的代码：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">const int i = 10;</span><br><span class="line">// 这里i已经被定义为常量，但是我们仍然可以通过另外的方式去修改它的值。</span><br><span class="line">// 这说明把i定义为常量，实际上是防止通过i去修改所代表的内存。</span><br><span class="line">int *pi = (int*) &amp;i;</span><br></pre></td></tr></table></figure>
<h1 id="C-Class-Const-Member-Variable"><a href="#C-Class-Const-Member-Variable" class="headerlink" title="C++ Class Const Member Variable"></a><strong>C++ Class Const Member Variable</strong></h1><p>const 修饰类的数据成员。如：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">class A</span><br><span class="line">&#123;</span><br><span class="line">	const int size;</span><br><span class="line">	…</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>const数据成员只在某个对象生存期内是常量，而对于整个类而言却是可变的。因为类可以创建多个对象，不同的对象其const数据成员的值可以不同。所以不能在类声明中初始化const数据成员，因为类的对象未被创建时，编译器不知道const 数据成员的值是什么。如</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">class A</span><br><span class="line">&#123;</span><br><span class="line">	const int size = 100;    //错误</span><br><span class="line">	int array[size];         //错误，未知的size</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>const数据成员的初始化只能在类的构造函数的初始化表中进行。要想建立在整个类中都恒定的常量，应该用类中的枚举常量来实现。如</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">class A</span><br><span class="line"></span><br><span class="line">&#123;</span><br><span class="line">	…</span><br><span class="line">	enum &#123;size1=100, size2 = 200 &#125;;</span><br><span class="line">	int array1[size1];</span><br><span class="line">	int array2[size2];</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>枚举常量不会占用对象的存储空间，他们在编译时被全部求值。但是枚举常量的隐含数据类型是整数，其最大值有限，且不能表示浮点数。</p>
<h1 id="C-Class-Const-Method"><a href="#C-Class-Const-Method" class="headerlink" title="C++ Class Const Method"></a><strong>C++ Class Const Method</strong></h1><p>常量函数是C++对常量的一个扩展，它很好的确保了C++中类的封装性。在C++中，为了防止类的数据成员被非法访问，将类的成员函数分成了两类，一类是常量成员函数（也被称为观察着）；另一类是非常量成员函数（也被成为变异者）。在一个函数的签名后面加上关键字const后该函数就成了常量函数。对于常量函数，最关键的不同是编译器不允许其修改类的数据成员。例如：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">class Test</span><br><span class="line">&#123;</span><br><span class="line">public:</span><br><span class="line">	void func() const;</span><br><span class="line">private:</span><br><span class="line">	int intValue;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">void Test::func() const</span><br><span class="line">&#123;</span><br><span class="line">	intValue = 100;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>上面的代码中，常量函数func函数内试图去改变数据成员intValue的值，因此将在编译的时候引发异常。</p>
<p>当然，对于非常量的成员函数，我们可以根据需要读取或修改数据成员的值。但是，这要依赖调用函数的对象是否是常量。通常，如果我们把一个类定义为常量，我们的本意是希望他的状态（数据成员）不会被改变。那么，如果一个常量的对象调用它的非常量函数会产生什么后果呢？看下面的代码：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">class Fred&#123;</span><br><span class="line">public:</span><br><span class="line">	void inspect() const;</span><br><span class="line">	void mutate();</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">void UserCode(Fred&amp; changeable, const Fred&amp; unChangeable)</span><br><span class="line">&#123;</span><br><span class="line">	changeable.inspect(); // 正确，非常量对象可以调用常量函数。</span><br><span class="line">	changeable.mutate(); // 正确，非常量对象也允许修改调用非常量成员函数修改数据成员。</span><br><span class="line">	unChangeable.inspect(); // 正确，常量对象只能调用常理函数。因为不希望修改对象状态。</span><br><span class="line">	unChangeable.mutate(); // 错误！常量对象的状态不能被修改，而非常量函数存在修改对象状态的可能</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>从上面的代码可以看出，由于常量对象的状态不允许被修改，因此，通过常量对象调用非常量函数时将会产生语法错误。实际上，我们知道每个成员函数都有一个隐含的指向对象本身的this指针。而常量函数则包含一个this的常量指针。如下：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">void inspect(const Fred* this) const;</span><br><span class="line">void mutate(Fred* this);</span><br></pre></td></tr></table></figure>
<p>也就是说对于常量函数，我们不能通过this指针去修改对象对应的内存块。但是，在上面我们已经知道，这仅仅是编译器的限制，我们仍然可以绕过编译器的限制，去改变对象的状态。看下面的代码：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">class Fred&#123;</span><br><span class="line">public:</span><br><span class="line">	void inspect() const;</span><br><span class="line">private:</span><br><span class="line">	int intValue;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">void Fred::inspect() const</span><br><span class="line">&#123;</span><br><span class="line">	cout &lt;&lt; &quot;At the beginning. intValue = &quot;&lt;&lt; intValue &lt;&lt; endl;</span><br><span class="line">	// 这里，我们根据this指针重新定义了一个指向同一块内存地址的指针。</span><br><span class="line">	// 通过这个新定义的指针，我们仍然可以修改对象的状态。</span><br><span class="line">	Fred* pFred = (Fred*)this;</span><br><span class="line">	pFred-&gt;intValue = 50;</span><br><span class="line">	cout &lt;&lt; &quot;Fred::inspect() called. intValue = &quot;&lt;&lt; intValue &lt;&lt; endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main()</span><br><span class="line">&#123;</span><br><span class="line">	Fred fred;</span><br><span class="line">	fred.inspect();</span><br><span class="line">	return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>上面的代码说明，只要我们愿意，我们还是可以通过常量函数修改对象的状态。同理，对于常量对象，我们也可以构造另外一个指向同一块内存的指针去修改它的状态。这里就不作过多描述了。</p>
<p>另外，也有这样的情况，虽然我们可以绕过编译器的错误去修改类的数据成员。但是C++也允许我们在数据成员的定义前面加上mutable，以允许该成员可以在常量函数中被修改。例如：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">class Fred&#123;</span><br><span class="line">public:</span><br><span class="line">	void inspect() const;</span><br><span class="line">private:</span><br><span class="line">	mutable int intValue;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">void Fred::inspect() const</span><br><span class="line">&#123;</span><br><span class="line">	intValue = 100;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>但是，并不是所有的编译器都支持mutable关键字。这个时候我们上面的歪门邪道就有用了。</p>
<p>关于常量函数，还有一个问题是重载。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;iostream&gt;</span><br><span class="line">#include &lt;string&gt;</span><br><span class="line">using namespace std;</span><br><span class="line">class Fred&#123;</span><br><span class="line">public:</span><br><span class="line">	void func() const;</span><br><span class="line">	void func();</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">void Fred::func() const</span><br><span class="line">&#123;</span><br><span class="line">	cout &lt;&lt; &quot;const function is called.&quot;&lt;&lt; endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void Fred::func()</span><br><span class="line">&#123;</span><br><span class="line">	cout &lt;&lt; &quot;non-const function is called.&quot;&lt;&lt; endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void UserCode(Fred&amp; fred, const Fred&amp; cFred)</span><br><span class="line">&#123;</span><br><span class="line">	cout &lt;&lt; &quot;fred is non-const object, and the result of fred.func() is:&quot; &lt;&lt; endl;</span><br><span class="line">	fred.func();</span><br><span class="line">	cout &lt;&lt; &quot;cFred is const object, and the result of cFred.func() is:&quot; &lt;&lt; endl;</span><br><span class="line">	cFred.func();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main()</span><br><span class="line">&#123;</span><br><span class="line">	Fred fred;</span><br><span class="line">	UserCode(fred, fred);</span><br><span class="line">	return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">输出结果为：</span><br><span class="line"></span><br><span class="line">fred is non-const object, and the result of fred.func() is:</span><br><span class="line">non-const function is called.</span><br><span class="line">cFred is const object, and the result of cFred.func() is:</span><br><span class="line">const function is called.</span><br></pre></td></tr></table></figure>
<p>从上面的输出结果，我们可以看出。当存在同名同参数和返回值的常量函数和非常量函数时，具体调用哪个函数是根据调用对象是常量对像还是非常量对象来决定的。常量对象调用常量成员；非常量对象调用非常量的成员。</p>
<p>总之，我们需要明白常量函数是为了最大程度的保证对象的安全。通过使用常量函数，我们可以只允许必要的操作去改变对象的状态，从而防止误操作对对象状态的破坏。但是，就像上面看见的一样，这样的保护其实是有限的。关键还是在于我们开发人员要严格的遵守使用规则。另外需要注意的是常量对象不允许调用非常量的函数。这样的规定虽然很武断，但如果我们都根据原则去编写或使用类的话这样的规定也就完全可以理解了。</p>
<p>const对象只能访问const成员函数，而非const对象可以访问任意的成员函数，包括const成员函数；</p>
<p>const对象的成员是不能修改的，而通过指针维护的对象确实可以修改的；</p>
<p>const成员函数不可以修改对象的数据，不管对象是否具有const性质。编译时以是否修改成员数据为依据进行检查。</p>
<h1 id="const修饰函数参数"><a href="#const修饰函数参数" class="headerlink" title="const修饰函数参数"></a><strong>const修饰函数参数</strong></h1><p>将函数传入参数声明为const，以指明使用这种参数仅仅是为了效率的原因，而不是想让调用函数能够修改对象的值。同理，将指针参数声明为const，函数将不修改由这个参数所指的对象。通常修饰指针参数和引用参数：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">void Fun( const A *in); //修饰指针型传入参数</span><br><span class="line">void Fun(const A &amp;in); //修饰引用型传入参数</span><br></pre></td></tr></table></figure>
<p><strong>注意</strong>：</p>
<h1 id="修饰函数返回值"><a href="#修饰函数返回值" class="headerlink" title="修饰函数返回值"></a><strong>修饰函数返回值</strong></h1><p>可以阻止用户修改返回值。返回值也要相应的付给一个常量或常指针。</p>
<h1 id="const在C和C-中的区别"><a href="#const在C和C-中的区别" class="headerlink" title="const在C和C++中的区别"></a><strong>const在C和C++中的区别</strong></h1><p>C++中的const正常情况下是看成编译期的常量,编译器并不为const分配空间,只是在编译的时候将期值保存在名字表中,并在适当的时候折合在代码中.所以,以下代码:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">using namespace std;</span><br><span class="line">int main()</span><br><span class="line">&#123;</span><br><span class="line">	const int a = 1;</span><br><span class="line">	const int b = 2;</span><br><span class="line">	int array[ a + b ] = &#123;0&#125;;</span><br><span class="line">	for (int i = 0; i &lt; sizeof array / sizeof *array; i++)</span><br><span class="line">	&#123;</span><br><span class="line">		cout &lt;&lt; array &lt;&lt; endl;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>在可以通过编译,并且正常运行.但稍加修改后,放在C编译器中,便会出现错误:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">int main()</span><br><span class="line">&#123;</span><br><span class="line">	int i;</span><br><span class="line">	const int a = 1;</span><br><span class="line">	const int b = 2;</span><br><span class="line">	int array[ a + b ] = &#123;0&#125;;</span><br><span class="line">	for (i = 0; i &lt; sizeof array / sizeof *array; i++)</span><br><span class="line">	&#123;</span><br><span class="line">		printf(&quot;%d&quot;,array);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>错误消息:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">c:\test1\te.c(8): error C2057: 应输入常数表达式</span><br><span class="line">c:\test1\te.c(8): error C2466: 不能分配常数大小为 0 的数组</span><br></pre></td></tr></table></figure>
<p>出现这种情况的原因是:在C中,const是一个不能被改变的普通变量,既然是变量,就要占用存储空间,所以编译器不知道编译时的值.而且,数组定义时的下标必须为常量.</p>
<p>在C语言中: const int size; 这个语句是正确的，因为它被C编译器看作一个声明,指明在别的地方分配存储空间.但在C++中这样写是不正确的.C++中const默认是内部连接,如果想在C++中达到以上的效果,必须要用extern关键字.即C++中,const默认使用内部连接.而C中使用外部连接.</p>
<p><strong>内连接</strong>:编译器只对正被编译的文件创建存储空间,别的文件可以使用相同的表示符或全局变量.C/C++中内连接使用static关键字指定.</p>
<p><strong>外连接</strong>:所有被编译过的文件创建一片单独存储空间.一旦空间被创建,连接器必须解决对这片存储空间的引用.全局变量和函数使用外部连接.通过extern关键字声明,可以从其他文件访问相应的变量和函数.</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">/* C++代码  header.h */</span><br><span class="line">const int test = 1;</span><br><span class="line"></span><br><span class="line">/* C++代码  test1.cpp */</span><br><span class="line">#include &quot;header.h&quot;</span><br><span class="line">using namespace std;</span><br><span class="line">int main() &#123;</span><br><span class="line">	cout &lt;&lt; &quot;in test1 :&quot; &lt;&lt; test &lt;&lt; endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/* C++代码 test2.cpp */</span><br><span class="line">#include &quot;header.h&quot;</span><br><span class="line">using namespace std;</span><br><span class="line">void print() &#123;</span><br><span class="line">	cout &lt;&lt; &quot;in test2:&quot; &lt;&lt; test &lt;&lt; endl;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>以上代码编译连接完全不会出问题,但如果把header.h改为:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">extern const int test = 1;</span><br></pre></td></tr></table></figure>
<p>在连接的时候,便会出现以下错误信息:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">test2 error LNK2005: &quot;int const test&quot; (?test@@3HB) 已经在 test1.obj 中定义</span><br></pre></td></tr></table></figure>
<p>因为extern关键字告诉C++编译器test会在其他地方引用,所以,C++编译器就会为test创建存储空间,不再是简单的存储在名字表里面.所以,当两个文件同时包含header.h的时候,会发生名字上的冲突.</p>
<p>此种情况和C中const含义相似:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">/* C代码 header.h */</span><br><span class="line">const int test = 1;</span><br><span class="line"></span><br><span class="line">/* C代码 test1.c */</span><br><span class="line">#include &quot;header.h&quot;</span><br><span class="line">int main() &#123;</span><br><span class="line">	printf(&quot;in test1:%d\n&quot;,test);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/* C代码 test2.c */</span><br><span class="line">#include &quot;header.h&quot;</span><br><span class="line">void print() &#123;</span><br><span class="line">	printf(&quot;in test2:%d\n&quot;,test);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>错误消息:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">test3 fatal error LNK1169: 找到一个或多个多重定义的符号</span><br><span class="line">test3 error LNK2005: _test 已经在 test1.obj 中定义</span><br></pre></td></tr></table></figure>
<p>也就是说：在c++ 中const 对象默认为文件的局部变量。与其他变量不同，除非特别说明，在全局作用域声明的 const 变量是定义该对象的文件的局部变量。此变量只存在于那个文件中，不能被其他文件访问。通过指定 const 变更为 extern，就可以在整个程序中访问 const 对象：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">// file_1.cc</span><br><span class="line">// defines and initializes a const that is accessible to other files</span><br><span class="line">extern const int bufSize = fcn();</span><br><span class="line"></span><br><span class="line">// file_2.cc</span><br><span class="line">extern const int bufSize; // uses bufSize from file_1</span><br><span class="line"></span><br><span class="line">// uses bufSize defined in file_1</span><br><span class="line">for (int index = 0; index != bufSize; ++index)</span><br><span class="line">	// ...</span><br></pre></td></tr></table></figure>
<p>C++中,是否为const分配空间要看具体情况.如果加上关键字extern或者取const变量地址,则编译器就要为const分配存储空间.</p>
<p>C++中定义常量的时候不再采用define,因为define只做简单的宏替换，并不提供类型检查.</p>
<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a><strong>总结</strong></h1><p>一般情况下，函数的返回值为某个对象时，如果将其声明为const时，多用于操作符的重载。通常，不建议用const修饰函数的返回值类型为某个对象或对某个对象引用的情况。原因如下：如果返回值为某个对象为const（const A test = A实例）或某个对象的引用为const（const A&amp; test = A实例），则返回值具有const属性，则返回实例只能访问类A中的公有（保护）数据成员和const成员函数，并且不允许对其进行赋值操作，这在一般情况下很少用到。</p>
<p>如果给采用“指针传递”方式的函数返回值加const修饰，那么函数返回值（即指针）的内容不能被修改，该返回值只能被赋给加const 修饰的同类型指针。如：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">const char * GetString(void);</span><br></pre></td></tr></table></figure>
<p>如下语句将出现编译错误：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">char *str=GetString();</span><br></pre></td></tr></table></figure>
<p>正确的用法是：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">const char *str=GetString();</span><br></pre></td></tr></table></figure>
<p>函数返回值采用“引用传递”的场合不多，这种方式一般只出现在类的赙值函数中，目的是为了实现链式表达。如：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">class A</span><br><span class="line">&#123;</span><br><span class="line">	…</span><br><span class="line">	A &amp;operate = (const A &amp;other);  //负值函数</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">A a,b,c;              //a,b,c为A的对象</span><br><span class="line">…</span><br><span class="line">a=b=c;            //正常</span><br><span class="line">(a=b)=c;          //不正常，但是合法</span><br></pre></td></tr></table></figure>
<p>若负值函数的返回值加const修饰，那么该返回值的内容不允许修改，上例中a=b=c依然正确。(a=b)=c就不正确了。</p>
<h2 id="类成员函数中const的使用"><a href="#类成员函数中const的使用" class="headerlink" title="类成员函数中const的使用"></a><strong>类成员函数中const的使用</strong></h2><p>一般放在函数体后，形如：void fun() const; 任何不会修改数据成员的函数都因该声明为const类型。如果在编写const成员函数时，不慎修改了数据成员，或者调用了其他非const成员函数，编译器将报错，这大大提高了程序的健壮性。如：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">class Stack</span><br><span class="line">&#123;</span><br><span class="line">	public:</span><br><span class="line">		void Push(int elem);</span><br><span class="line">		int Pop(void);</span><br><span class="line">		int GetCount(void) const;   //const 成员函数</span><br><span class="line">	private:</span><br><span class="line">		int m_num;</span><br><span class="line">		int m_data[100];</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">int Stack::GetCount(void) const</span><br><span class="line">&#123;</span><br><span class="line">	++m_num;              //编译错误，企图修改数据成员m_num</span><br><span class="line">	Pop();                    //编译错误，企图调用非const函数</span><br><span class="line">	Return m_num;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="使用const的一些建议"><a href="#使用const的一些建议" class="headerlink" title="使用const的一些建议"></a><strong>使用const的一些建议</strong></h2><ol>
<li>要大胆的使用const，这将给你带来无尽的益处，但前提是你必须搞清楚原委；</li>
<li>要避免最一般的赋值操作错误，如将const变量赋值，具体可见思考题；</li>
<li>在参数中使用const应该使用引用或指针，而不是一般的对象实例，原因同上；</li>
<li>const在成员函数中的三种用法（参数、返回值、函数）要很好的使用；</li>
<li>不要轻易的将函数的返回值类型定为const;</li>
<li>除了重载操作符外一般不要将返回值类型定为对某个对象的const引用;</li>
</ol>

      
    </div>

    

    
    
    

    

    
      
    
    

    

    <footer class="post-footer">
      
        <div class="post-tags">
          
            <a href="/tags/C/" rel="tag"># C++</a>
          
        </div>
      

      
      
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/2016/08/06/jottings/平凡的世界/" rel="next" title="平凡的世界">
                <i class="fa fa-chevron-left"></i> 平凡的世界
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/2016/08/06/tech/静态方法和实例化方法/" rel="prev" title="怎么理解C++面向对象的静态方法和实例化方法">
                怎么理解C++面向对象的静态方法和实例化方法 <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </div>
  
  
  
  </article>


  </div>


          </div>
          

  
    <div class="comments" id="comments">
    </div>

  



        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap">
            文章目录
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview-wrap">
            站点概览
          </li>
        </ul>
      

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
            
              <img class="site-author-image" itemprop="image" src="/images/logo1.jpg" alt="方林">
            
              <p class="site-author-name" itemprop="name">方林</p>
              <div class="site-description motion-element" itemprop="description">愿你出走半生，归来仍是少年</div>
          </div>

          
            <nav class="site-state motion-element">
              
                <div class="site-state-item site-state-posts">
                
                  <a href="/archives/">
                
                    <span class="site-state-item-count">27</span>
                    <span class="site-state-item-name">日志</span>
                  </a>
                </div>
              

              
                
                
                <div class="site-state-item site-state-categories">
                  
                    
                      <a href="/categories/">
                    
                  
                    
                    
                      
                    
                      
                    
                      
                    
                    <span class="site-state-item-count">3</span>
                    <span class="site-state-item-name">分类</span>
                  </a>
                </div>
              

              
                
                
                <div class="site-state-item site-state-tags">
                  
                    
                      <a href="/tags/">
                    
                  
                    
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                    <span class="site-state-item-count">17</span>
                    <span class="site-state-item-name">标签</span>
                  </a>
                </div>
              
            </nav>
          

          
            <div class="feed-link motion-element">
              <a href="/atom.xml" rel="alternate">
                <i class="fa fa-rss"></i>
                RSS
              </a>
            </div>
          

          

          
            <div class="links-of-author motion-element">
              
                <span class="links-of-author-item">
                  
                  
                    
                  
                  
                    
                  
                  <a href="https://github.com/yourname" title="GitHub &rarr; https://github.com/yourname" rel="noopener" target="_blank"><i class="fa fa-fw fa-github"></i>GitHub</a>
                </span>
              
                <span class="links-of-author-item">
                  
                  
                    
                  
                  
                    
                  
                  <a href="mailto:sean_ps@163.com" title="E-Mail &rarr; mailto:sean_ps@163.com" rel="noopener" target="_blank"><i class="fa fa-fw fa-envelope"></i>E-Mail</a>
                </span>
              
            </div>
          

          

          
          
            <div class="links-of-blogroll motion-element links-of-blogroll-block">
              <div class="links-of-blogroll-title">
                <i class="fa  fa-fw fa-link"></i>
                Links
              </div>
              <ul class="links-of-blogroll-list">
                
                  <li class="links-of-blogroll-item">
                    <a href="http://www.luoo.net" title="http://www.luoo.net" rel="noopener" target="_blank">落网</a>
                  </li>
                
              </ul>
            </div>
          

          
            
          
          

        </div>
      </div>

      
      <!--noindex-->
        <div class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc">

            
            
            
            

            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#概述"><span class="nav-number">1.</span> <span class="nav-text">概述</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#常量"><span class="nav-number">2.</span> <span class="nav-text">常量</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#指针和常量"><span class="nav-number">3.</span> <span class="nav-text">指针和常量</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#常量和引用"><span class="nav-number">4.</span> <span class="nav-text">常量和引用</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#C-Class-Const-Member-Variable"><span class="nav-number">5.</span> <span class="nav-text">C++ Class Const Member Variable</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#C-Class-Const-Method"><span class="nav-number">6.</span> <span class="nav-text">C++ Class Const Method</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#const修饰函数参数"><span class="nav-number">7.</span> <span class="nav-text">const修饰函数参数</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#修饰函数返回值"><span class="nav-number">8.</span> <span class="nav-text">修饰函数返回值</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#const在C和C-中的区别"><span class="nav-number">9.</span> <span class="nav-text">const在C和C++中的区别</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#总结"><span class="nav-number">10.</span> <span class="nav-text">总结</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#类成员函数中const的使用"><span class="nav-number">10.1.</span> <span class="nav-text">类成员函数中const的使用</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#使用const的一些建议"><span class="nav-number">10.2.</span> <span class="nav-text">使用const的一些建议</span></a></li></ol></li></ol></div>
            

          </div>
        </div>
      <!--/noindex-->
      

      

    </div>
  </aside>
  


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright">&copy; <span itemprop="copyrightYear">2019</span>
  <span class="with-love" id="animate">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">fanglin</span>

  

  
</div>









        








        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

    

    

    
  </div>

  

<script>
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>


























  
  <script src="/lib/jquery/index.js?v=2.1.3"></script>

  
  <script src="/lib/velocity/velocity.min.js?v=1.2.1"></script>

  
  <script src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>


  


  <script src="/js/utils.js?v=7.1.0"></script>

  <script src="/js/motion.js?v=7.1.0"></script>



  
  


  <script src="/js/affix.js?v=7.1.0"></script>

  <script src="/js/schemes/pisces.js?v=7.1.0"></script>



  
  <script src="/js/scrollspy.js?v=7.1.0"></script>
<script src="/js/post-details.js?v=7.1.0"></script>



  


  <script src="/js/next-boot.js?v=7.1.0"></script>


  

  

  

  
  

<script src="//cdn1.lncld.net/static/js/3.11.1/av-min.js"></script>



<script src="//unpkg.com/valine/dist/Valine.min.js"></script>

<script>
  var GUEST = ['nick', 'mail', 'link'];
  var guest = 'nick,mail,link';
  guest = guest.split(',').filter(function(item) {
    return GUEST.indexOf(item) > -1;
  });
  new Valine({
    el: '#comments',
    verify: true,
    notify: false,
    appId: 'jjdDCzDO6jlN5yOgAbnVwdJ3-gzGzoHsz',
    appKey: 'jnjP7aorboCG7pJV6HvdMP15',
    placeholder: 'ヾﾉ≧∀≦)o来啊，快活啊!',
    avatar: 'mm',
    meta: guest,
    pageSize: '10' || 10,
    visitor: false,
    lang: 'zh-cn' || 'zh-cn'
  });
</script>




  


  




  

  

  

  

  

  

  

  

  

  

  

  

  

  

</body>
</html>
